/**
 * Elite JinXing WebSocket CTIProxy Client
 * Created by Jeff on 2018/03/20.
 */
define([$E.softphoneBasePath + "/softphone/softphone.constants" + $E.jsv], function($CTI_CONST){
/*
	var Connection = {
		STATE_IDLE : 0,
		STATE_RINGING : 1,
		STATE_DIALING : 2,
		STATE_TALKING : 3,
		STATE_HELD : 4,
		createNew:function(){
			var connection = {};
			connection.state = Connection.STATE_UNKONW;
			connection.connectionid = "";
			return connection;
		}
	};
*/

/*
	var CallInfo = {
		CALLTYPE_UNKNOWN : 0,
		CALLTYPE_INBOUND : 1,
		CALLTYPE_OUTBOUND : 2,
		createNew:function(){
			var callinfo = {};
			callinfo.activecall = null;
			callinfo.heldcall = null;
			callinfo.calltype = CallInfo.CALLTYPE_UNKNOWN;
			callinfo.tpreleased = 0;
			callinfo.starttime = null;
			callinfo.establishtime = null;
			callinfo.endtime = null;
			return callinfo;
		}
	};
*/	
	var MSGTYPE = $CTI_CONST.CTI_MSG;
	
	function addJsonStringValue(jsonobj, name, value)
	{
		var data = {};
		data.type = 3; //string
		data.value = value;
		jsonobj[name.toLowerCase()] = data;
	}

	function addJsonIntValue(jsonobj, name, value)
	{
		var data = {};
		data.type = 1; //int
		data.value = value;
		jsonobj[name.toLowerCase()] = data;
	}

	function addJsonDatasValue(jsonobj, name, value)
	{
		var data = {};
		data.type = 5; //datas
		data.value = value;
		jsonobj[name.toLowerCase()] = data;
	}

	function getJsonString(jsonobj, name)
	{
		if(jsonobj.hasOwnProperty(name)){
			return jsonobj[name];
		}
		return "";
	}

    function isJson(content){
    	try {
            var jsonStr= JSON.parse(content);
            return true;
    	} catch (e) {
            return false;
    	}
    }

	function isArray(object) {
	    return  object && typeof object==='object' &&    
	            typeof object.length==='number' &&  
	            typeof object.splice==='function' &&    
	             //判断length属性是否是可枚举的 对于数组 将得到false  
	            !(object.propertyIsEnumerable('length'));
	}
	
    function getdatabykey(datas, key) {
    	var d = datas
    	try {
    		if (typeof(d) == 'string') {
    			d = JSON.parse(d);
    		}
    		if (d) {
				for (var vkey in d) {
    				if (vkey.toLowerCase() == key.toLowerCase()) {
    					if (typeof(d)=='object') {
    						if (d.hasOwnProperty('value')) {
    							return d[vkey].value;
    						} else {
    							return d[vkey];
    						}
    					} else {
    						return d[vkey];
    					}
    				}
    			}		    			
    		}
	    } catch (err) {
    		
    	}
    }

    function tosimpleuserdata(datas, keyvaluesplit) {
    	if (!keyvaluesplit) {
    		keyvaluesplit = "=";
    	}
    	//将随路数据同一成JSON对象。特别地，如果随路数据中包含raw_data或uu_data，则只保留这部分内容
    	try {
    		if (typeof(datas) == 'string') {
    			datas = JSON.parse(datas);
    		}
    		var uui = getdatabykey(datas, 'uu_data');
    		if (uui) {
    			return {'uui' : uui};
    		} else {
    			var uui = getdatabykey(datas, 'raw_data');
    		}
			if (uui) {
				try {
					uui = JSON.parse(uui);
				} catch (err) {
					
				}
				return uui;
			} else {
				//return datas;
				var uui = '';
				var v;
				for (var p in datas) {
					if (datas[p].hasOwnProperty('value')) {
						v = tosimpledata(datas[p].value);
					} else {
						v = datas[p];
					}
					uui = uui + '|' + p + keyvaluesplit + v;
				}
				uui = uui.substring(1);
				return {'uui': uui};
			}
    	} catch (err) {
    		return {'uui' : datas};
    	}
    }
    
    function tosimpledata(data) {
    	try {
    		if (typeof(data) == 'object') {
        		var jdata = {};
        		for (var p in data) {
        			if (data[p].hasOwnProperty('value')) {
            			jdata[p] = tosimpledata(data[p].value);
        			} else {
        				jdata[p] = data[p];
        			}
        		}
        		return jdata;
    		} else {
    			return data;
    		}
    	} catch (err) {
    		return data;
    	}
    }

    function commonreplace(template, args) {
        if (arguments.length > 1 && typeof arguments[0] === "string") {
            var result = arguments[0];
            if (arguments.length == 2 && typeof arguments[1] === "object") {
                var obj = arguments[1];
                for (var key in obj) {
                    if (obj[key] != undefined) {
                        var reg = new RegExp("({" + key + "})", "g");
                        result = result.replace(reg, obj[key]);
                    }
                }
            } else {
                for (var i = 1, len = arguments.length; i < len; i++) {
                    if (arguments[i] != undefined) {
                        // 这个在索引大于9时会有问题
                        // var reg = new RegExp("({[" + (i - 1) + "]})", "g");
                        var reg = new RegExp("({)" + (i - 1) + "(})", "g");
                        result = result.replace(reg, arguments[i]);
                    }
                }
            }
            return result;
        } else {
            return arguments[0];
        }
    }
    
    var ELITEJXCTIClient = {
		createNew : function(){

			var softphone = {};	
			softphone.logined = false;
			softphone.logoutbeforelogin  = 0;
			softphone.keepalivetimer = 0;
			softphone.invokeid = 0;
			softphone.rqqueue = {};
			softphone.currentdest = "";
			softphone.dn = "";
			softphone.channelid = 1;
			softphone.agentid = "";
			softphone.agentpassword = "";
			softphone.agentgroup = "";
			//softphone.activeid = "";
			//softphone.heldid = "";
			//softphone.spydest = "";
			//softphone.callinfo = CallInfo.createNew();
			
			softphone.lastdevice = null;

			var keyvaluesplit = '=';

		    var Error = function (error, args) {
		        return this.init(error, args);
		    };
		    Error.UNKNOW_ERROR = {
	            code: 80000,
	            name: "UNKNOW_ERROR",
	            message: "未知错误"
	        };
		    Error.INVOKE_TIMEOUT = {
		        code: 80100,
		        name: "INVOKE_TIMEOUT",
		        message: "请求超时 - {method}"
		    };
		    Error.NO_DEVICE_INFO = {
		        code: 80110,
		        name: "NO_DEVICE_INFO",
		        message: "未获取到分机信息"
		    };
		    Error.INVALID_DEVICE_ID = {
		        code: 80111,
		        name: "INVALID_DEVICE_ID",
		        message: "无效的分机号：{deviceId}"
		    };
		    Error.EXIST_DEVICE_LOGIN = {
		        code: 80112,
		        name: "EXIST_DEVICE_LOGIN",
		        message: "分机已登录，登录工号：{agentId}",
		    };
		    Error.RESOURCE_BUSY = {
		        code: 80113,
		        name: "RESOURCE_BUSY",
		        message: "分机正在通话"
		    };

		    Error.INVALID_AGENT_ID = {
		        code: 80121,
		        name: "INVALID_AGENT_ID",
		        message: "无效的工号：{agentId}"
		    };
		    Error.INVALID_PASSWORD = {
	            code: 80122,
	            name: "INVALID_PASSWORD",
	            message: "无效的密码"
	        };
		    Error.EXIST_AGENT_LOGIN = {
		        code: 80123,
		        name: "EXIST_AGENT_LOGIN",
		        message: "工号已登录，登录分机：{deviceId}"
		    };
		    Error.prototype = {
	            constructor: Error,
	            init: function (error, args) {
	                var newError = null;
	                if (typeof error === "object") {
	                    if (typeof args != undefined) {
	                        newError = Object.create(error);
	                        for (var name in newError) {
	                            newError[name] = commonreplace(newError[name], args);
	                        }
	                    } else {
	                        newError = error;
	                    }
	                } else if (typeof error === "string") {
	                    newError = {
	                        code: 80999,
	                        name: "Error",
	                        message: error
	                    };
	                }
	                return newError;
	            }
	        };

		    softphone.OnCTIEvent = function(evt) {
				this.logmsg("[OnCTIEvent]:" + evt);
				var datas = JSON.parse(evt);
/*
				switch(parseInt(datas.event.value)){
					//tbd 2018036, why linkconnected == 1?
					case 12: //linkconnected
						this.OnLinkConnected(datas);
						break;
					case 16: //registered
						this.OnRegistered(datas);
						break;
					case 20: //dialing
						this.OnDialing(datas);
						break;
					case 3: //released
						this.OnReleased(datas);
						break;
					case 2: //established
						this.OnEstablished(datas);
						break;
					case 6: //held
						this.OnHeld(datas);
						break;
					case 7: //retrieved
						this.OnRetrieved(datas);
						break;
				}
*/				
				//this.FireCTIEvent(datas);
				this.OnMessage(datas)
			}
					
			softphone.initjxsession = function()
			{
				var d = new Date();
				var t = d.getTime();
				//var request="{method:\"initSession\",object:\"cti\",params:[\"\",\"softphone"+";"+t+"\",\"\",\"Async\"]}";
				var request = {};
				request.method = "initSession";
				request.object = "cti";
				var params = [];
				params[0] = "";
				params[1] = "softphone;"+t;
				params[2] = "";
				params[3] = "Async";
				request.params = params;
				var msg = JSON.stringify(request);
				this.SendJXRequest(msg, request.method);
			}

			softphone.InternalOnError = function(errMessage, errorCode, errorName)
			{
				var ret = {};
				addJsonIntValue(ret, "event", MSGTYPE.EVT_ERROR);
	        	addJsonIntValue(ret, "dn", this.dn);
	        	addJsonIntValue(ret, "channelid", this.channelid);
	        	if (!errorCode) {
	        		errorCode = 80001
	        	}
	        	addJsonIntValue(ret, "errorcode", errorCode);
	        	addJsonStringValue(ret, "errordesc", errMessage);
	        	if (errorName) {
	        		addJsonStringValue(ret, "errorname", errorName);
	        	}
	            return ret;
			}
			softphone.OnInitSessionResponse = function(jsonobj)
			{
				var ret = {};
				
				addJsonIntValue(ret, "event", MSGTYPE.EVT_LINKCONNECTED);
				//start timer
				this.keepalivetimer = setInterval(this.keepalive, 60000);
	        	return ret;
			}
			softphone.OnMonitorDeviceResponse = function(jsonobj)
			{
				var ret = {};
				addJsonIntValue(ret, "dn", this.dn);
	        	addJsonIntValue(ret, "channelid", this.channelid);
	        	addJsonIntValue(ret, "event", MSGTYPE.EVT_REGISTERED);
	        	return ret;
			}
			softphone.OnInitDesktop = function(jsonobject)
			{
				this.logmsg("desktop init,login agent");
	            var jsonobj = {};
	            jsonobj.method = "setAgentState";
	            jsonobj.object = "cti";
	            var loginparams = {};
	            loginparams.reason = "0";
	            loginparams.agentId = this.agentid;
	            loginparams.deviceId = this.dn;
	            loginparams.func = "Login";
	            loginparams.password = this.agentpassword;
	            loginparams.group = this.agentgroup;
	            loginparams.agentMode = "NotReady";
	            var array = [];
	            array[0] = loginparams;
	            jsonobj.params = array;
	            var msg = JSON.stringify(jsonobj);
	            this.SendJXRequest(msg, jsonobj.method);
			}

			softphone.OnSnapshotDevice = function(jsonobject) {
				this.logmsg('onsnapshotdevice::' + JSON.stringify(jsonobject));
				if (m_logon_step = 1) {
					
				}
			}
			
			softphone.OnAgentLogin = function()
			{
				this.logined = true;
				var ret = {};
	            addJsonIntValue(ret, "event", MSGTYPE.EVT_AGENTLOGIN);
	            addJsonIntValue(ret, "workmode", 3);
	            addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            return ret;
			}
			
			softphone.OnAgentNotReady = function(jsonobj)
			{
				this.logined = true;
	            var reasoncode = "";
	            var ret = {};
	            addJsonIntValue(ret, "event", MSGTYPE.EVT_AGENTNOTREADY);
	            addJsonIntValue(ret, "workmode", 3);
	            addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	             
	            if (jsonobj.hasOwnProperty("properties"))
	            {
	                var properties = jsonobj.properties;
	                reasoncode = properties.reason;
	                addJsonIntValue(ret, "reasoncode", reasoncode);
	            }
	            return ret;   
			}
			softphone.OnAgentReady = function(jsonobj)
			{
				this.logined = true;
				var ret = {};
	            addJsonIntValue(ret, "event", MSGTYPE.EVT_AGENTREADY);
	            addJsonIntValue(ret, "workmode", 2);
	            addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            return ret;
			}
			softphone.OnAgentLogout = function(jsonobj)
			{
				if (this.logoutbeforelogin == 1) {
					this.logoutbeforelogin = 2;
					return;
				}
				this.logined = false;
				var ret = {};
				addJsonIntValue(ret, "event", MSGTYPE.EVT_AGENTLOGOUT);
				addJsonIntValue(ret, "workmode", 0);
				addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            
	            softphone.unRegisterDN();
	            return ret;
			}
			softphone.OnOriginated = function(jsonobj)
			{
				var ret = {};
				addJsonIntValue(ret, "event", MSGTYPE.EVT_DIALING);
				addJsonIntValue(ret, "workmode", 0);
				addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            var properties = jsonobj.properties;
	            
	            var calleddevice = getJsonString(properties, "calledDevice");
				if(calleddevice != ""){
					addJsonStringValue(ret, "otherdn", calleddevice);
				}
	            var callid = getJsonString(properties, "callId");
	            this.activeid = callid;
	            addJsonStringValue(ret, "callid", callid);
	            if (this.heldid && this.heldid != callid) {
	            	addJsonStringValue(ret, "prevconnectionid", this.heldid);
	            }
	            return ret;
			}
			softphone.OnDelivered = function(jsonobj)
			{
				var ret = {};
	            
				addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            var properties = jsonobj.properties;
	            var alertingdevice = getJsonString(properties, "alertingDevice");
	            if (alertingdevice == this.dn)
	            {
	            	addJsonIntValue(ret, "event", MSGTYPE.EVT_RINGING);
	                var calleddevice = getJsonString(properties, "calledDevice");
	                addJsonStringValue(ret, "dnis", calleddevice);
	                var callingdevice = getJsonString(properties, "callingDevice");
	                addJsonStringValue(ret, "ani", callingdevice);
	                var callid = getJsonString(properties, "callId");
	                addJsonStringValue(ret, "callid", callid);
	                this.activeid = callid;
	                var ucid = getJsonString(properties, "contactId");
	                addJsonStringValue(ret, "ucid", ucid);
	                var originalucid = getJsonString(properties, "originalContactId");
	                if (originalucid == '00000000000000000000') {
	                	originalucid = '';
	                }
	                addJsonStringValue(ret, 'originalucid', originalucid);
	                var userdatas = {};
	                
	                if (properties.hasOwnProperty("userData"))
	                {
	                    var userdata = properties.userData;
	                    if (userdata.hasOwnProperty("map"))
	                    {
	                        var mapdata = userdata.map;
	                        
	                        for(var name in mapdata)
	                        {
	                            //userdatas.AddData(name, mapdata[name]);
	                        	//userdatas[name] = mapdata[name];
	                        	if (name == 'uui') {
		                        	addJsonStringValue(userdatas, "rawdata", mapdata[name]);
	                        		try {
	                        			if (mapdata[name].indexOf(keyvaluesplit) && mapdata[name].indexOf('|')) {
	                        				var data1 = mapdata[name].split('|');
	                        				for(var i=0; i<data1.length; i++) {
	                        					var data2 = data1[i].split(keyvaluesplit);
	                        					if (data2.length == 2) {
	                        						addJsonStringValue(userdatas, data2[0], data2[1]);
	                        					} else {
	                        						data2 = data1[i].split("\\u003d");
		                        					if (data2.length == 2) {
		                        						addJsonStringValue(userdatas, data2[0], data2[1]);
		                        					}	
	                        					}
	                        				}
	                        			}
	                        		} catch (err) {
	                        			
	                        		}
	                        	} else {
		                        	addJsonStringValue(userdatas, name, mapdata[name]);
	                        	}
	                        }
	                    }
	                }
	                addJsonStringValue(userdatas, "ucid", ucid);
	                addJsonStringValue(userdatas, "originalucid", originalucid);
	                addJsonDatasValue(ret, "userdata", userdatas);
	            }
	            else
	            {
	            	addJsonIntValue(ret, "event", MSGTYPE.EVT_RINGBACK);
	                var callid = getJsonString(properties, "callId");
	                addJsonStringValue(ret, "callid", callid);
	                this.activeid = callid;
	            }
	            return ret;
			}
			softphone.OnEstablished = function(jsonobj)
			{
				var ret = {};
				addJsonIntValue(ret, "event", MSGTYPE.EVT_ESTABLISH);
				addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            var properties = jsonobj.properties;
	            var callid = getJsonString(properties, "callId");
	            addJsonStringValue(ret, "callid", callid);
	            if (this.heldid && this.heldid != callid) {
	            	addJsonStringValue(ret, "prevconnectionid", this.heldid);
	            }
	            var ucid = getJsonString(properties, "contactId");
	            addJsonStringValue(ret, "ucid", ucid);
	            var userdatas = {};
	            addJsonStringValue(userdatas, "ucid", ucid);
	            addJsonDatasValue(ret, "userdata", userdatas);
	            return ret;
			}
			softphone.OnConnectionCleared = function(jsonobj)
			{
				var ret = {};
				addJsonStringValue(ret, "dn", this.dn);
				addJsonIntValue(ret, "channelid", this.channelid);
	            var properties = jsonobj.properties;
	            var connectionState = getJsonString(properties, "connectionState");
	            var releasingdevice = getJsonString(properties, "releasingDevice");
	            if (connectionState == "Idle" || connectionState == "None")
	            {
	            	addJsonIntValue(ret, "event", MSGTYPE.EVT_RELEASED);
	                var callid = getJsonString(properties, "callId");
	                addJsonStringValue(ret, "callid", callid);

	                if (callid == this.activeid)
	                {
	                    this.activeid = "";
	                }
	                else if (callid == this.heldid)
	                {
	                    this.heldid = "";
	                    
	                }
	                if (releasingdevice == this.dn)
	                {
	                	addJsonIntValue(ret, "tpreleased", 1);
	                }
	                else
	                {
	                	addJsonIntValue(ret, "tpreleased", 0);
	                }
	            }
	            else
	            {
	            	addJsonIntValue(ret, "event", MSGTYPE.EVT_PARTYDELETED);
	            	addJsonStringValue(ret, "deletedparty", releasingdevice);
	            }
	            return ret;
			}
			softphone.OnHeld=function(jsonobj)
			{
				var ret = {};
	            var properties = jsonobj.properties;
	            var holdingdevice = getJsonString(properties, "holdingDevice");
	            
	            addJsonIntValue(ret, "event", MSGTYPE.EVT_HELD);
	            addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            addJsonStringValue(ret, "holdingdevice", holdingdevice);
	            var callid = getJsonString(properties, "callId");
	            this.heldid = callid;
	            addJsonStringValue(ret, "callid", callid);
	            if(callid == this.activeid){
	                this.activeid = "";
	            }
	            return ret;
			}
			softphone.OnRetrieved = function(jsonobj)
			{
				var ret = {};
	            var properties = jsonobj.properties;
	            addJsonIntValue(ret, "event", MSGTYPE.EVT_RETRIEVED);
	            addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            
	            var callid = getJsonString(properties, "callId");
	            this.activeid = callid;
	            addJsonStringValue(ret, "callid", callid);
	            if (callid == this.heldid)
	            {
	                this.heldid = "";
	            }
	            return ret;
			}
			softphone.OnTransferred = function(jsonobj) {
				var ret = [];
				var properties = jsonobj.properties;
	            var transferringDevice = getJsonString(properties, "transferringDevice");
	            
	            if (transferringDevice == this.dn) {
	                var evt = {};
	                addJsonStringValue(evt, "DN", this.dn);
	                addJsonIntValue(evt, "channelid", this.channelid);
	                addJsonIntValue(evt, "event", MSGTYPE.EVT_RELEASED);
	                var primaryOldCallID=getJsonString(properties, "primaryOldCall");
	                addJsonStringValue(evt, "callid", primaryOldCallID);
	                addJsonStringValue(evt, "transferreleased", 1);
	                ret[0] = evt;
	                var evt2 = {};
	                addJsonStringValue(evt2, "dn", this.dn);
	                addJsonIntValue(evt2, "channelid", this.channelid);
	                addJsonIntValue(evt2, "event", MSGTYPE.EVT_RELEASED);
	                var secondaryOldCallID = getJsonString(properties, "secondaryOldCall");
	                addJsonStringValue(evt2, "callid", secondaryOldCallID);
	                addJsonIntValue(evt2, "transferreleased", 1);
	                ret[1] = evt2;
	                this.activeid = "";
	                this.heldid = "";
	            } else {
	                var evt = {};
	                addJsonStringValue(evt, "dn", this.dn);
	                addJsonIntValue(evt, "channelid", this.channelid);
	                addJsonIntValue(evt, "event", MSGTYPE.EVT_PARTYCHANGED);
	                var primaryOldCallID=getJsonString(properties, "primaryOldCall");
			        var secondaryOldCallID = getJsonString(properties, "secondaryOldCall");
			        addJsonStringValue(evt, "activecallid", secondaryOldCallID);
			        addJsonStringValue(evt, "heldcallid", primaryOldCallID);
	                ret[0] = evt;
	                if (this.activeid == primaryOldCallID) {
	                	this.activeid = secondaryOldCallID;
	                } else if (this.heldid == primaryOldCallID) {
	                	this.heldid = secondaryOldCallID
	                }
	            }
	            return ret;
			}
			softphone.OnConferenced = function(jsonobj)
			{
				var ret = {};
				var properties = jsonobj.properties;
				addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            var cause=getJsonString(properties, "cause");
	            addJsonIntValue(ret, "event", MSGTYPE.EVT_CONFERENCED);
	            if(cause == "31"){
	            	addJsonIntValue(ret, "SILENTMONITOR", 1);
		        }
	            var primaryOldCallID=getJsonString(properties, "primaryOldCall");
	            var secondaryOldCallID = getJsonString(properties, "secondaryOldCall");
	            addJsonStringValue(ret, "activecallid", secondaryOldCallID);
	            addJsonStringValue(ret, "heldcallid", primaryOldCallID);
	            
	            addJsonStringValue(ret, "callid", this.activeid);
	            if (this.heldid && this.heldid != this.activeid) {
	            	addJsonStringValue(ret, "prevconnectionid", this.heldid);
	            }

	            var addedParty=getJsonString(properties, "addedParty");
		        if(addedParty != ""){
		        	addJsonStringValue(ret, "addedparty", addedParty);
	            }
	            var contactid=getJsonString(properties, "contactId");
	            var userdatas = {};
	            addJsonStringValue(ret, "ucid", contactid);
	            addJsonDatasValue(ret, "userdata", userdatas);
	            return ret;
			}
			softphone.OnAgentACW = function(jsonobj)
			{
				var ret = {};
				this.logined = true;
	            var properties = jsonobj.properties;
	            var reasoncode = getJsonString(properties, "reason");
	            addJsonIntValue(ret, "event", MSGTYPE.EVT_AGENTNOTREADY);
	            addJsonIntValue(ret, "workmode", 4);
	            addJsonStringValue(ret, "dn", this.dn);
	            addJsonIntValue(ret, "channelid", this.channelid);
	            return ret;
			}
			softphone.OnSessionClosed = function(jsonobj)
			{
				var ret = {};
				this.logined = true;
				addJsonIntValue(ret, "event", MSGTYPE.EVT_LINKDISCONNECTED);
				return ret;
			}
			
			softphone.translatejxevt = function(msg)
			{
				this.logmsg("Receive event:" + msg);
				var ret;
				try{
	                if (msg.length > 64)
	                {
	                    var json = msg.substr(64);
	                    var msgtype = msg.substring(4, 6);
	                    this.logmsg("json:" + json);
	                    var jsonobj = JSON.parse(json);
	                    if (jsonobj.hasOwnProperty("method"))
	                    {
	                        var method = jsonobj.method;
	                        var errmessage = jsonobj.errMessage;
	                        if (errmessage != undefined && errmessage.length != 0)
	                        {
	                        	if (msgtype != '11') {
		                        	ret = this.InternalOnError(errmessage);
	                        	}
	                        } else if (method == "initSession") {
	                            ret = this.OnInitSessionResponse(jsonobj);
	                        } else if (method == "monitorDevice") {
	                            ret = this.OnMonitorDeviceResponse(jsonobj);
	                        } else if (method == "initDesktop") {
	                            this.OnInitDesktop(jsonobj);
	                        } else if (method == "snapshotDevice") {
	                        	this.OnSnapshotDevice(jsonobj);
	                        }
	                    }
	                    else if (jsonobj.hasOwnProperty("name"))
	                    {
	                        var name = jsonobj.name;
	                        if (name == "agentLoggedOn")
	                        {
	                            ret = this.OnAgentLogin();
	                        }
	                        else if (name == "agentNotReady"){
	                            ret = this.OnAgentNotReady(jsonobj);
	                        
	                        }else if(name == "agentReady")
	                        {
	                            ret = this.OnAgentReady(jsonobj);
	                        }else if(name == "agentLoggedOff")
	                        {
	                            ret = this.OnAgentLogout(jsonobj);
	                        }
	                        else if (name == "originated")
	                        {
	                            ret = this.OnOriginated(jsonobj);
	                        }
	                        else if (name == "delivered")
	                        {
	                            ret = this.OnDelivered(jsonobj);
	                        }
	                        else if (name=="established")
	                        {
	                            ret = this.OnEstablished(jsonobj);
	                        }
	                        else if (name == "connectionCleared")
	                        {
	                            ret = this.OnConnectionCleared(jsonobj);
	                        }
	                        else if (name == "held")
	                        {
	                            ret = this.OnHeld(jsonobj);
	                        }
	                        else if (name == "retrieved")
	                        {
	                            ret = this.OnRetrieved(jsonobj);
	                        }
	                        else if (name == "transferred")
	                        {
	                            ret = this.OnTransferred(jsonobj);
	                        }
	                        else if (name == "conferenced")
	                        {
	                            ret = this.OnConferenced(jsonobj);
	                        }else if(name == "agentWorkingAfterCall")
	                        {
	                            ret = this.OnAgentACW(jsonobj);
	                        }else if(name == "SessionClosed")
	                        {
	                        	ret = this.OnSessionClosed(jsonobj);
	                        }
	                    }
	                    else if (jsonobj.hasOwnProperty("errMessage"))
	                    {
	                        OnError(jsonobj);
	                    }
	                    else
	                    {
	                        log.debug("unhandled message " + json);
	                    }

	                	//var msgtype = msg.substring(4, 6);
	                	var invokeid1 = Number(msg.substring(14, 22))
	                	
	                	if (msgtype == '10') {
	                		//send request and success
	                        var invoke = softphone.rqqueue[invokeid1];
	                        if (!invoke) {
	                        	return;
	                        }
	                        // 清除超时检测定时器
	                        softphone.stopCheckTimedOut(invokeid1);

	                        invoke.resolve(jsonobj.ret);
	                        // this.onsuccess(response.data,
	                        // invoke.options.success);
	                	} else if (msgtype == '11') {
	                		//send request and fail
	                        var invoke = softphone.rqqueue[invokeid1];
	                        if (!invoke) {
	                        	ret = this.InternalOnError(errmessage);
	                        	return ret;
	                        }
	                        softphone.stopCheckTimedOut(invokeid1);
	                        var msg = jsonobj.errMessage;
	                        var error = null;
	                        if (!msg || msg == "null") {
	                            error = new Error(Error.UNKNOW_ERROR);
	                        } else if (msg.match(/invalid deviceid:/)) {
	                            error = new Error(Error.INVALID_DEVICE_ID, {
	                                deviceId: msg.match(/[^invalid deviceid:]+/)
	                            });
	                        } else if (msg.match(/invalid agent id:/)) {
	                            error = new Error(Error.INVALID_AGENT_ID, {
	                                agentId: msg.match(/[^invalid agent id:]+/)
	                            });
	                        } else if (msg.match(/invalid password/)) {
	                            error = new Error(Error.INVALID_PASSWORD, {
	                            });
	                        } else if (msg.match(/CTIException/)) {
	                            //var name = msg.match(/CTIException\(\(\d+\)\s(.*)\):.*/)[1];
	                            //if ($.Error[name]) {
	                            //    error = new Error(Error[name]);
	                            //} else {
	                        		try {
		                                var code = Number(msg.match(/CTIException\(\((\d+).*/)[1]);
		                                var name = msg.match(/CTIException\(\(\d+\)\s(.*)\):.*/)[1];
		                                error = new Error({
		                                    code: code,
		                                    name: name,
		                                    message: "CTI请求异常(" + code + ")" + name
		                                });
	                        		} catch(e) {
	                        			error = new Error({
	                        				code: new Error({
	                        					code: 80000,
	                        					name: "CTIException",
	                        					message: msg.substr(msg.lastIndexOf("CTIException"))
	                        				})
	                        			})
	                        		}
	                            //}
	                        } else {
	                            error = new Error(msg);
	                        }
	                        invoke.reject(error);
	                        ret = softphone.InternalOnError(error.message, error.code, error.name);
	                	}
	                	
	                }
	                else
	                {
	                    log.error("wrong format less than 64 bytes");
	                }
	            }catch(e){
	                this.logmsg("[OnWSEvent]:" + e.message);
	               	throw e;
	            }
	            return ret;
			}
			softphone.keepalive = function()
			{
				//softphone.logmsg("Send KeepAlive");
		        var jsonobj = {"method" : "heartbeat", "object" : "cti"};
		        softphone.SendJXRequest(JSON.stringify(jsonobj));
			}

			softphone.connectserver = function(serverendpoint, onOpen, onClose, onMessage, onError, onSendMessage){
				keyvaluesplit = $SC.getConfig('CTI', 'KeyValueSplit');
				if (!keyvaluesplit) {
					keyvaluesplit = '=';
				}
				
				softphone.websocket = new WebSocket(serverendpoint);
				softphone.websocket.onopen = function(evt){
					//onOpen(evt);
					softphone.initjxsession();
				}
				softphone.websocket.onclose = function(evt){
					if(softphone.keeptimer!=0){
						clearInterval(softphone.keepalivetimer);
						softphone.keepalivetimer = 0;
					}
					onClose(evt);
				}
				softphone.websocket.onmessage = function(evt){
					softphone.logmsg("receive event" + evt.data);
					var msg=softphone.translatejxevt(evt.data);
					if(typeof(msg) != "undefined"){
						if(isArray(msg)){
							for(var i=0; i<msg.length; i++){
								var s = JSON.stringify(msg[i]);
								softphone.OnCTIEvent(s);
								//onMessage(s);
							}
						}else{
							var s = JSON.stringify(msg);
							softphone.OnCTIEvent(s);
							//onMessage(s);
						}
					}
				}
				softphone.websocket.onerror = function(evt){
					onError(evt);
				}
				softphone.OnSendMessage = onSendMessage;
				//softphone.FireCTIEvent = OnCTIEvent;
				softphone.OnMessage = onMessage;
				softphone.OnError = onError;
			};
			
			softphone.SendJXRequest = function(request, method)
			{
				var msg = "CT4001";
			    var msglen = request.length;
			    msg += softphone.LeftFill("" + msglen, 8, "0");
			    this.invokeid++;
			    msg += softphone.LeftFill("" + softphone.invokeid, 8, "0");
			    //msg += "\r\n";
			    msg = softphone.RightFill(msg, 64, " ");
			    msg += request.toString();

			    var timeout = 30000;
	            var promise = new Promise(function (resolve, reject) {
	                // 向请求队列中添加对象
	                softphone.rqqueue[softphone.invokeid] = {
	                    // 超时检测定时器
	                    timer: null,
	                	method : method,
	                	msg : msg,
	                    resolve: resolve,
	                    reject: reject
	                };
	                softphone.checkTimedOut(softphone.invokeid, timeout);

	                softphone.logmsg("Begin send request:"+msg);
	                softphone.websocket.send(msg);
				    softphone.logmsg("msg sent");
				    softphone.OnSendMessage(msg);
	            });
	            return promise;			
			}

			softphone.SendJXRequest2 = function(method, params)
			{
				var msg = "CT4001";
				var request = JSON.stringify({
					method: method,
					object: 'cti',
					params: params
				})
			    var msglen = request.length;
			    msg += softphone.LeftFill("" + msglen, 8, "0");
			    this.invokeid++;
			    msg += softphone.LeftFill("" + softphone.invokeid, 8, "0");
			    //msg += "\r\n";
			    msg = softphone.RightFill(msg, 64, " ");
			    msg += request.toString();

			    var timeout = 30000;
	            var promise = new Promise(function (resolve, reject) {
	                // 向请求队列中添加对象
	                softphone.rqqueue[softphone.invokeid] = {
	                    // 超时检测定时器
	                    timer: null,
	                	method : method,
	                	msg : msg,
	                    resolve: resolve,
	                    reject: reject
	                };
	                softphone.checkTimedOut(softphone.invokeid, timeout);

	                softphone.logmsg("Begin send request:"+msg);
				    softphone.websocket.send(msg);
				    softphone.logmsg("msg sent");
				    softphone.OnSendMessage(msg);
	            });
	            return promise;			
			}
			
			softphone.checkTimedOut = function (invokeId, timeout) {
	            var invoke = softphone.rqqueue[invokeId];
	            if (invoke) {
		            invoke.timer = window.setTimeout(function () {
		                if (invoke.method == "close") return;
		                softphone.logmsg("timeout - " + invoke.msg);
		                // 发送超时消息
		                invoke.reject(new Error(Error.INVOKE_TIMEOUT, {
		                    method: invoke.method
		                }));
		                // 删除请求队列中的对象
		                delete softphone.rqqueue[invokeId];
		            }, timeout);
	            }
	        }
	        
	        softphone.stopCheckTimedOut = function (invokeid) {
	            var invoke = softphone.rqqueue[invokeid];
	            if (invoke && invoke.timer) {
	                window.clearTimeout(invoke.timer);
	                invoke.timer = 0;
	            }
	            delete softphone.rqqueue[invokeid];
	        }
			
			softphone.logmsg = function(msg)
			{
				console.log("[softphone_jx]"+msg);
			}
			
			softphone.LeftFill = function(s, len, fillchar)
			{
				var ret = "";
				for (var i = s.length; i < len; i++)
				{
					ret = ret + fillchar;;
			    }
				return ret + s;
			}
			
			softphone.RightFill = function(s,len,fillchar)
			{
				var ret = "";
				for (var i = s.length; i < len; i++)
				{
					ret=ret + fillchar;;
				}
				return s + ret;
			}

			softphone.registerdn = function(dn)
		    {
		    	this.dn=dn;
		    	/*
		    	var jsonobj = {};
		        jsonobj.method="monitorDevice";
		        jsonobj.object="cti";
		        var array = [];
		        array[0]=dn;
		        jsonobj.params=array;
		        var msg=JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		        */
		    	softphone.lastdevice = null;
		    	softphone.queryStationByDeviceId(dn)
		    	.then(function (device) {
		    		//debugger;
		    		softphone.lastdevice = device;
			        softphone.SendJXRequest2('monitorDevice', [dn])
		    	}, function (e) {
		    		//debugger;
		    		//softphone.InternalOnError(e.message, e.code, e.name);
		    	}) 
		    };
		    softphone.unRegisterDN = function()
		    {
		    	softphone.SendJXRequest2('stopMonitorDevice', [this.dn])
		    	.then(function (e) {
		    		softphone.lastdevice = null;
		    	}, function (e) {
		    		
		    	})
		    }
			    
		    //REQ_SETAGENTLOGIN = 84
			softphone.login = function(agentid,dn,agentpassword,agentgroup,workmode,acdagent)
			{
			    this.agentid = agentid;
			    this.agentpassword = agentpassword;
		    	this.agentgroup = agentgroup;
		    	this.dn = dn;
		    	/*
		    	var jsonobj = {};
		        jsonobj.method = "initDesktop";
		        jsonobj.object = "cti";
		        var array = [];
		        array[0] = this.agentid;
		        array[1] = this.dn;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		        */
	    		//debugger;
	    		var err;
	    		var reterr;
	    		if (softphone.lastdevice) {
		    		if (softphone.lastdevice.calls.length) {
		    			err = new Error(Error.RESOURCE_BUSY);
		    			reterr = softphone.InternalOnError(err.message, err.code, err.name);
		    		} else if (softphone.lastdevice.agent && softphone.lastdevice.agent.agentId != agentid) {
		    			err = new Error(new Error(Error.EXIST_DEVICE_LOGIN, {agentId: softphone.lastdevice.agent.agentId}))
		    			reterr = softphone.InternalOnError(err.message, err.code, err.name);
		    		}
		    		if (reterr) {
		    			softphone.unRegisterDN();
						softphone.OnCTIEvent(JSON.stringify(reterr));
						return;
		    		}
	    		}
		    	softphone.queryStationByAgentId(agentid)
		    	.then(function (agent) {
		    		if (agent && agent.agentMode != "Logout") {
                        if (agent.deviceId != dn) {
                        	err = new Error(Error.EXIST_AGENT_LOGIN, {deviceId: agent.deviceId});
                        	reterr = softphone.InternalOnError(err.message, err.code, err.name);
                        	softphone.OnCTIEvent(JSON.stringify(reterr));
                        	return;
                        }
                        softphone.logoutbeforelogin = 1;
                        softphone.agentlogout_(agentid, dn, agentpassword)
                        .then(function (e) {
                        	var iCount = 0;
                        	function checkLogoutTimer(){
                        		setTimeout(function(){
                        			if (softphone.logoutbeforelogin == 1) {
                        				iCount++;
                            			if(iCount > 100) {
                                        	err = new Error(Error.EXIST_AGENT_LOGIN, {deviceId: agent.deviceId});
                                        	reterr = softphone.InternalOnError(err.message, err.code, err.name);
                                        	softphone.OnCTIEvent(JSON.stringify(reterr));
                            			} else {
                            				checkLogoutTimer();
                            			}
                        			} else {
                				        softphone.SendJXRequest2('initDesktop', [agentid, dn])
                        			}
                        		}, 100);
                        	};
                        	checkLogoutTimer();
                        	return;
                        	//softphone.SendJXRequest2('initDesktop', [agentid, dn]);
                        }, function(e) {
                        	err = new Error(Error.EXIST_AGENT_LOGIN, {deviceId: agent.deviceId});
                        	reterr = softphone.InternalOnError(err.message, err.code, err.name);
                        	softphone.OnCTIEvent(JSON.stringify(reterr));
                        	return;
                        });
                    };
			        softphone.SendJXRequest2('initDesktop', [agentid, dn])
		    	}, function (e) {
		    		//debugger;
		    		//softphone.InternalOnError(e.message, e.code, e.name);
		    	})
		    }

		    //REQ_SETAGENTLOGOUT = 87
		    softphone.agentlogout = function(){
		    	var jsonobj = {};
		        jsonobj.method = "setAgentState";
		        jsonobj.object = "cti";
		        var notreadyparams = {};
		        notreadyparams.reason = "0";
		        notreadyparams.agentId = this.agentid;
		        notreadyparams.deviceId = this.dn;
		        notreadyparams.func = "Logout";
		        notreadyparams.password = this.agentpassword;
		        notreadyparams.group = null;
		        notreadyparams.agentMode = "Logout";
		        
		        var array = [];
		        array[0] = notreadyparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        softphone.logoutbeforelogin = 0;
		        this.SendJXRequest(msg, jsonobj.method);
		    }

		    softphone.agentlogout_ = function(agentid, dn, passw){
		        return this.SendJXRequest2('setAgentState', [{reason: '0' , agentId: agentid, deviceId: dn, group: '', func: 'Logout', password: passw, agentMode: 'Logout'}]);
		    }
			    
		    //REQ_SETAGENTNOTREADY = 86
		    softphone.agentnotready = function(workmode)
		    {
		    	if (workmode == 4) {
		    		return softphone.acw();
		    	}
		    	this.aux(0);
		    }

		    softphone.aux = function(reasoncode)
			{

		    	var jsonobj = {};
		        jsonobj.method = "setAgentState";
		        jsonobj.object = "cti";
		        var notreadyparams = {};
		        if (isNaN(reasoncode) || Number(reasoncode) < 0) {
		        	reasoncode = "0";
		        }
		        notreadyparams.reason="" + reasoncode;
		        notreadyparams.agentId = this.agentid;
		        notreadyparams.deviceId = this.dn;
		        notreadyparams.func = "SetState";
		        notreadyparams.password = this.agentpassword;
		        notreadyparams.group = null;
		        notreadyparams.agentMode = "NotReady";
		        var array = [];
		        array[0] = notreadyparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		    }

		    softphone.acw = function()
		    {
		    	/*var request='{"request":{"type":1,"value":"86"},"dn":{"type":3,"value":"'+this.dn+'"},"workmode":{"type":1,"value":"'+AGENTWORKMODE.ACW+'"},"agentid":{"type":3,"value":"'+this.agentid+'"},"password":{"type":3,"value":"'+this.agentpassword+'"},"agentgroup":{"type":3,"value":"'+this.agentgroup+'"}}';
		    	this.websocket.send(request);
		    	this.OnSendMessage(request);*/
		    	var jsonobj = {};
		        jsonobj.method = "setAgentState";
		        jsonobj.object = "cti";
		        var notreadyparams = {};
		        notreadyparams.reason = "0";
		        notreadyparams.agentId = this.agentid;
		        notreadyparams.deviceId = this.dn;
		        notreadyparams.func = "SetState";
		        notreadyparams.password = this.password;
		        notreadyparams.group = null;
		        notreadyparams.agentMode = "WorkNotReady";
		        var array = [];
		        array[0] = notreadyparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		    }

		    //REQ_SETAGENTREADY = 85
		    softphone.agentready = function(workmode){
		    	/*var request='{"request":{"type":1,"value":"85"},"dn":{"type":3,"value":"'+this.dn+'"},"workmode":{"type":1,"value":"'+AGENTWORKMODE.MANUALIN+'"},"agentid":{"type":3,"value":"'+this.agentid+'"},"password":{"type":3,"value":"'+this.agentpassword+'"},"agentgroup":{"type":3,"value":"'+this.agentgroup+'"}}';
		    	this.websocket.send(request);
		    	this.OnSendMessage(request);*/
		    	var jsonobj = {};
		        jsonobj.method = "setAgentState";
		        jsonobj.object = "cti";
		        var notreadyparams = {};
		        notreadyparams.reason = "0";
		        notreadyparams.agentId = this.agentid;
		        notreadyparams.deviceId = this.dn;
		        notreadyparams.func = "SetState";
		        notreadyparams.password = this.agentpassword;
		        notreadyparams.group = null;
		        notreadyparams.agentMode = "Ready";
		        var array = [];
		        array[0] = notreadyparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);

		    }

		    //REQ_MAKECALL = 90,
		    softphone.makecall = function(dest, userdatas)
		    {
		    	this.currentdest = dest.trim();
		        var jsonobj = {};
		        jsonobj.method = "makeCall";
		        jsonobj.object = "cti";
		        var callparams = {};
		        callparams.deviceId = this.dn;
		        callparams.orgin = this.dn;
		        callparams.dest = dest;
		        var array = [];
		        array[0] = callparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		    }

		    //REQ_RELEASECALL = 91,
		    softphone.releasecall = function(callid)
		    {
		    	var id = "";
		    	if (callid) {
		    		id = callid;
		    	}	/*else{
		    		if(this.callinfo.activecall != null){
		    			id=this.callinfo.activecall.connectionid;
		    		}
		    	}*/
		    	if(id != ""){
		    		var jsonobj = {};
		            jsonobj.method = "clearConnection";
		            jsonobj.object = "cti";
		            var callparams = {};
		            callparams.deviceId = this.dn;
		            callparams.callId = id;
		            var array = [];
		            array[0] = callparams;
		            jsonobj.params = array;
		            var msg=JSON.stringify(jsonobj);
		            this.SendJXRequest(msg, jsonobj.method);
			    }
		    }

		    //REQ_HOLDCALL = 92,
		    softphone.holdcall=function(callid)
		    {
		    	var id = "";
		    	if (callid) {
		    		id = callid;
		    	}	/* else{
		    		if(this.callinfo.activecall!=null){
		    			id=this.callinfo.activecall.connectionid;
		    		}
		    	} */
		    	if(id != "") {
		    		var jsonobj = {};
		            jsonobj.method = "holdCall";
		            jsonobj.object = "cti";
		            var callparams = {};
		            callparams.deviceId = this.dn;
		            callparams.callId = id;
		            var array = [];
		            array[0] = callparams;
		            jsonobj.params = array;
		            var msg=JSON.stringify(jsonobj);
		            this.SendJXRequest(msg, jsonobj.method);
			    }
		    }

		    softphone.answercall = function(callid)
		    {
		    	var id = "";
		    	if (callid) {
		    		id = callid;
		    	} /*else {
		    		if (this.callinfo.activecall !=null) {
		    			id = this.callinfo.activecall.connectionid;
		    		}
		    	} */
		    	if (id != "") {
		    		var jsonobj = {};
		            jsonobj.method = "answerCall";
		            jsonobj.object = "cti";
		            var callparams = {};
		            callparams.deviceId = this.dn;
		            callparams.callId = id;
		            var array = [];
		            array[0] = callparams;
		            jsonobj.params = array;
		            var msg = JSON.stringify(jsonobj);
		            this.SendJXRequest(msg, jsonobj.method);
			    }
		    }

		    softphone.retrievecall = function(callid)
		    {
		    	var id = "";
		    	if (callid) {
		    		id = callid;
		    	} /*else {
		    		if (this.callinfo.heldcall != null) {
		    			id = this.callinfo.heldcall.connectionid;
		    		}
		    	} */
		    	if(id != "") {
			    	/*var request='{"request":{"type":1,"value":"93"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+id+'"}}';
			    	this.websocket.send(request);
			    	this.OnSendMessage(request);*/
		    		var jsonobj = {};
		            jsonobj.method = "retrieveCall";
		            jsonobj.object = "cti";
		            var callparams = {};
		            callparams.deviceId = this.dn;
		            callparams.callId = id;
		            var array = [];
		            array[0] = callparams;
		            jsonobj.params = array;
		            var msg = JSON.stringify(jsonobj);
		            this.SendJXRequest(msg, jsonobj.method);
			    }
		    }
			    
	        //REQ_INITTRANSFER = 94,
		    softphone.inittransfer = function(callid, dest, userdatas)
		    {
		    	return this.consultationcall(callid, dest, userdatas);
		    }
	        //REQ_INITCONFERENCE = 95,
		    softphone.initconference = function(callid, dest, userdatas)
		    {
		    	return this.consultationcall(callid, dest, userdatas);
		    }

		    softphone.consultationcall = function(callid, dest, datas)
		    {
		    	var jsonobj = {};
		        jsonobj.method = "consultationCall";
		        jsonobj.object = "cti";
		        var callparams = {};
		        callparams.deviceId = this.dn;
		        callparams.existingCall = callid;
		        callparams.consultedDevice = dest;
		        var mapobj = {};
		        mapobj.map = tosimpleuserdata(datas, keyvaluesplit);
		        callparams.userData = mapobj;
		        var array = [];
		        array[0] = callparams;
		        jsonobj.params = array;
		        var msg=JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		    }
			    
		    softphone.completetransfer = function(callid, heldcallid)
		    {
		    	var jsonobj = {};
		        jsonobj.method = "transferCall";
		        jsonobj.object = "cti";
		        var callparams = {};
		        callparams.deviceId = this.dn;
		        callparams.activeCall = callid;
		        callparams.heldCall = heldcallid;
		        var array = [];
		        array[0] = callparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		    }

		    softphone.completeconference = function(callid, heldcallid)
		    {
		    	var jsonobj = {};
		        jsonobj.method = "conferenceCall";
		        jsonobj.object = "cti";
		        var callparams = {};
		        callparams.deviceId = this.dn;
		        callparams.activeCall = callid;
		        callparams.heldCall = heldcallid;
		        var array = [];
		        array[0] = callparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		    };
			    
			softphone.singlesteptransfer = function(callid, dest, datas)
			{
				var jsonobj = {};
			    jsonobj.method="singleStepTransferCall";
			    jsonobj.object="cti";
			    var callparams = {};
			    callparams.deviceId = this.dn;
			    callparams.activeCall = callid;
			    callparams.transferredTo = dest;
/*			    
			    var uuiobj = {};
			    if (isJson(datas))
			    {
			        uuiobj = JSON.parse(datas);
			    } else {
			    	uuiobj.uui = datas;
			    }
*/			    
			    var mapobj = {};
			    mapobj.map = tosimpleuserdata(datas, keyvaluesplit);
			    callparams.userData = mapobj;
			    var array = [];
			    array[0] = callparams;
			    jsonobj.params = array;
			    var msg = JSON.stringify(jsonobj);
			    this.SendJXRequest(msg, jsonobj.method);
			}

			softphone.mutetransfer = function(callid, dest, datas)
			{
				return this.singlesteptransfer(callid, dest, datas);
			}
		    
			softphone.reconnect = function(callid, heldcallid)
		    {
		    	var jsonobj = {};
		        jsonobj.method = "reconnectCall";
		        jsonobj.object = "cti";
		        var callparams = {};
		        callparams.deviceId = this.dn;
		        callparams.activeCallId = callid;
		        callparams.heldCallId = heldcallid;
		        var array = [];
		        array[0] = callparams;
		        jsonobj.params = array;
		        var msg = JSON.stringify(jsonobj);
		        this.SendJXRequest(msg, jsonobj.method);
		    }
		    
	        softphone.queryStationByDeviceId = function (deviceId, agentId) {
	        	softphone.logmsg("queryStationByDeviceId:" + deviceId);
	            return softphone.SendJXRequest2("snapshotDevice", [{deviceId: deviceId, func: 1, syncAtOnce: false}])
	            .then(function (e) {
	                if (!(e).device) {
	                    return Promise.reject(new Error(Error.NO_DEVICE_INFO));
	                } else {
	                    return Promise.resolve(e.device);
	                }
	            });
	        }
	        
	        softphone.queryStationByAgentId = function (agentId) {
	        	softphone.logmsg("queryStationByAgentId:" + agentId);
	            return softphone.SendJXRequest2("snapshotDevice", [{agentId: agentId, func: 1, syncAtOnce: false}])
	            .then(function (e) {
	                return Promise.resolve(e.device);
	            });
	        }

	        return softphone;
		}
	};
	
	return ELITEJXCTIClient.createNew();
	
});
